Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / core / domain / src / commonTest / kotlin / org / meshtastic / core / domain / usecase / settings / ExportNodeDatabaseUseCaseTest.kt

Displaying Raw • Download

core/domain/src/commonTest/kotlin/org/meshtastic/core/domain/usecase/settings/ExportNodeDatabaseUseCaseTest.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 6.75 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.domain.usecase.settings

Tff7b72import T7ee787kotlinx.coroutines.test.runTest
Tff7b72import T7ee787kotlinx.serialization.json.Json
Tff7b72import T7ee787kotlinx.serialization.json.JsonObject
Tff7b72import T7ee787kotlinx.serialization.json.boolean
Tff7b72import T7ee787kotlinx.serialization.json.double
Tff7b72import T7ee787kotlinx.serialization.json.float
Tff7b72import T7ee787kotlinx.serialization.json.int
Tff7b72import T7ee787kotlinx.serialization.json.jsonArray
Tff7b72import T7ee787kotlinx.serialization.json.jsonObject
Tff7b72import T7ee787kotlinx.serialization.json.jsonPrimitive
Tff7b72import T7ee787kotlinx.serialization.json.long
Tff7b72import T7ee787okio.Buffer
Tff7b72import T7ee787okio.ByteString.Companion.encodeUtf8
Tff7b72import T7ee787org.meshtastic.core.model.Node
Tff7b72import T7ee787org.meshtastic.core.testing.FakeNodeRepository
Tff7b72import T7ee787org.meshtastic.core.testing.TestDataFactory
Tff7b72import T7ee787org.meshtastic.proto.DeviceMetrics
Tff7b72import T7ee787org.meshtastic.proto.HardwareModel
Tff7b72import T7ee787org.meshtastic.proto.Position
Tff7b72import T7ee787org.meshtastic.proto.User
Tff7b72import T7ee787kotlin.test.BeforeTest
Tff7b72import T7ee787kotlin.test.Test
Tff7b72import T7ee787kotlin.test.assertEquals
Tff7b72import T7ee787kotlin.test.assertFalse
Tff7b72import T7ee787kotlin.test.assertNull
Tff7b72import T7ee787kotlin.test.assertTrue

Tff7b72class T56d364ExportNodeDatabaseUseCaseTest Tb4b4b4{

Tff7b72private Tff7b72lateinit Tff7b72var Te6edf3nodeRepositoryTb4b4b4: Te6edf3FakeNodeRepository
Tff7b72private Tff7b72lateinit Tff7b72var Te6edf3useCaseTb4b4b4: Te6edf3ExportNodeDatabaseUseCase

Tf0883e@BeforeTest
Tff7b72fun Td2a8ffsetUpTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3nodeRepository Tff7b72= Te6edf3FakeNodeRepositoryTb4b4b4(Tb4b4b4)
Te6edf3useCase Tff7b72= Te6edf3ExportNodeDatabaseUseCaseTb4b4b4(Te6edf3nodeRepositoryTb4b4b4)
Tb4b4b4}

Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffexportJsonTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3JsonObject Tb4b4b4{
Tff7b72val Te6edf3buffer Tff7b72= Te6edf3BufferTb4b4b4(Tb4b4b4)
Te6edf3useCaseTb4b4b4(Te6edf3bufferTb4b4b4)
Tff7b72return Te6edf3JsonTb4b4b4.Te6edf3parseToJsonElementTb4b4b4(Te6edf3bufferTb4b4b4.Te6edf3readUtf8Tb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3jsonObject
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`empty database exports a valid document`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3root Tff7b72= Te6edf3exportJsonTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3rootTff7b72[Ta5d6ff"Ta5d6ffschemaVersionTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3intTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3rootTff7b72[Ta5d6ff"Ta5d6ffexportedAtTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3contentTb4b4b4.Te6edf3orEmptyTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3rootTff7b72[Ta5d6ff"Ta5d6ffmyNodeNumTa5d6ff"Tff7b72]Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3rootTff7b72[Ta5d6ff"Ta5d6ffnodesTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonArrayTff7b72?.Te6edf3sizeTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`absent readings are omitted rather than exported as sentinels`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
T8b949e// A bare node: snr/rssi hold their unset sentinels, lastHeard is 0, and no metrics were ever received.
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff2Tb4b4b4)Tb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3node Tff7b72= Te6edf3exportJsonTb4b4b4(Tb4b4b4)Tff7b72[Ta5d6ff"Ta5d6ffnodesTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonArrayTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3jsonObject

Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff2Tb4b4b4, Te6edf3nodeTff7b72[Ta5d6ff"Ta5d6ffnumTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3intTb4b4b4)
Te6edf3assertFalseTb4b4b4(Ta5d6ff"Ta5d6ffsnrTa5d6ff" Tff7b72in Te6edf3nodeTb4b4b4)
Te6edf3assertFalseTb4b4b4(Ta5d6ff"Ta5d6ffrssiTa5d6ff" Tff7b72in Te6edf3nodeTb4b4b4)
Te6edf3assertFalseTb4b4b4(Ta5d6ff"Ta5d6fflastHeardTa5d6ff" Tff7b72in Te6edf3nodeTb4b4b4)
Te6edf3assertFalseTb4b4b4(Ta5d6ff"Ta5d6ffpositionTa5d6ff" Tff7b72in Te6edf3nodeTb4b4b4)
Te6edf3assertFalseTb4b4b4(Ta5d6ff"Ta5d6ffdeviceMetricsTa5d6ff" Tff7b72in Te6edf3nodeTb4b4b4)
Te6edf3assertFalseTb4b4b4(Ta5d6ff"Ta5d6ffenvironmentMetricsTa5d6ff" Tff7b72in Te6edf3nodeTb4b4b4)
Te6edf3assertFalseTb4b4b4(Ta5d6ff"Ta5d6ffpublicKeyTa5d6ff" Tff7b72in Te6edf3nodeTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`zero readings are real and survive the export`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
T8b949e// 0 dB SNR and 0 dBm RSSI are genuine measurements, not absence.
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff7Tb4b4b4, Te6edf3snr Tff7b72= T79c0ff0fTb4b4b4, Te6edf3rssi Tff7b72= T79c0ff0Tb4b4b4, Te6edf3lastHeard Tff7b72= T79c0ff1T79c0ff7T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3node Tff7b72= Te6edf3exportJsonTb4b4b4(Tb4b4b4)Tff7b72[Ta5d6ff"Ta5d6ffnodesTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonArrayTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3jsonObject

Te6edf3assertEqualsTb4b4b4(T79c0ff0fTb4b4b4, Te6edf3nodeTff7b72[Ta5d6ff"Ta5d6ffsnrTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3floatTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3nodeTff7b72[Ta5d6ff"Ta5d6ffrssiTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3intTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1T79c0ff7T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0LTb4b4b4, Te6edf3nodeTff7b72[Ta5d6ff"Ta5d6fflastHeardTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3longTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`node fields map through user position metrics and key`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3key Tff7b72= Ta5d6ff"Ta5d6ff0123456789abcdef0123456789abcdefTa5d6ff"Tb4b4b4.Te6edf3encodeUtf8Tb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3node Tff7b72=
Te6edf3NodeTb4b4b4(
Te6edf3num Tff7b72= T79c0ff7Tb4b4b4,
Te6edf3user Tff7b72=
Te6edf3UserTb4b4b4(
Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!00000007Ta5d6ff"Tb4b4b4,
Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffBase CampTa5d6ff"Tb4b4b4,
Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffBASETa5d6ff"Tb4b4b4,
Te6edf3hw_model Tff7b72= Te6edf3HardwareModelTb4b4b4.Te6edf3TBEAMTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3position Tff7b72= Te6edf3PositionTb4b4b4(Te6edf3latitude_i Tff7b72= T79c0ff4T79c0ff5T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0Tb4b4b4, Te6edf3longitude_i Tff7b72= Tff7b72-T79c0ff9T79c0ff3T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Te6edf3deviceMetrics Tff7b72= Te6edf3DeviceMetricsTb4b4b4(Te6edf3battery_level Tff7b72= T79c0ff8T79c0ff5Tb4b4b4, Te6edf3voltage Tff7b72= T79c0ff3.9fTb4b4b4)Tb4b4b4,
Te6edf3publicKey Tff7b72= Te6edf3keyTb4b4b4,
Te6edf3isFavorite Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3viaMqtt Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3hopsAway Tff7b72= T79c0ff2Tb4b4b4,
Te6edf3notes Tff7b72= Ta5d6ff"Ta5d6ffsolar repeaterTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3exported Tff7b72= Te6edf3exportJsonTb4b4b4(Tb4b4b4)Tff7b72[Ta5d6ff"Ta5d6ffnodesTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonArrayTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3jsonObject

Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ff!00000007Ta5d6ff"Tb4b4b4, Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffidTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3contentTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffBase CampTa5d6ff"Tb4b4b4, Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6fflongNameTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3contentTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffBASETa5d6ff"Tb4b4b4, Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffshortNameTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3contentTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffTBEAMTa5d6ff"Tb4b4b4, Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffhwModelTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3contentTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3keyTb4b4b4.Te6edf3base64Tb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffpublicKeyTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3contentTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffisFavoriteTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3boolean Tff7b72=Tff7b72= Tff7b72trueTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffviaMqttTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3boolean Tff7b72=Tff7b72= Tff7b72trueTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffhopsAwayTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3intTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffsolar repeaterTa5d6ff"Tb4b4b4, Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffnotesTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3contentTb4b4b4)

Tff7b72val Te6edf3position Tff7b72= Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffpositionTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonObject
Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff5.0Tb4b4b4, Te6edf3positionTff7b72[Ta5d6ff"Ta5d6fflatitudeTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonPrimitiveTb4b4b4.Te6edf3doubleTb4b4b4, Te6edf3absoluteTolerance Tff7b72= T79c0ff1e-6Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Tff7b72-T79c0ff9T79c0ff3.0Tb4b4b4, Te6edf3positionTff7b72[Ta5d6ff"Ta5d6fflongitudeTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonPrimitiveTb4b4b4.Te6edf3doubleTb4b4b4, Te6edf3absoluteTolerance Tff7b72= T79c0ff1e-6Tb4b4b4)

Tff7b72val Te6edf3metrics Tff7b72= Te6edf3exportedTff7b72[Ta5d6ff"Ta5d6ffdeviceMetricsTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonObject
Te6edf3assertEqualsTb4b4b4(T79c0ff8T79c0ff5Tb4b4b4, Te6edf3metricsTff7b72[Ta5d6ff"Ta5d6ffbatteryLevelTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3intTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3.9fTb4b4b4, Te6edf3metricsTff7b72[Ta5d6ff"Ta5d6ffvoltageTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3floatTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`node numbers export as unsigned`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3TestDataFactoryTb4b4b4.Te6edf3createMyNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= Tff7b72-T79c0ff2Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= Tff7b72-T79c0ff1Tb4b4b4)Tb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3root Tff7b72= Te6edf3exportJsonTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff2T79c0ff9T79c0ff4T79c0ff9T79c0ff6T79c0ff7T79c0ff2T79c0ff9T79c0ff4LTb4b4b4, Te6edf3rootTff7b72[Ta5d6ff"Ta5d6ffmyNodeNumTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3longTb4b4b4)
Tff7b72val Te6edf3node Tff7b72= Te6edf3rootTff7b72[Ta5d6ff"Ta5d6ffnodesTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonArrayTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3jsonObject
Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff2T79c0ff9T79c0ff4T79c0ff9T79c0ff6T79c0ff7T79c0ff2T79c0ff9T79c0ff5LTb4b4b4, Te6edf3nodeTff7b72[Ta5d6ff"Ta5d6ffnumTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3longTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`nodes are sorted most recently heard first`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(
Te6edf3listOfTb4b4b4(Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1Tb4b4b4, Te6edf3lastHeard Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4, Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff2Tb4b4b4, Te6edf3lastHeard Tff7b72= T79c0ff3T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4, Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff3Tb4b4b4, Te6edf3lastHeard Tff7b72= T79c0ff2T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72val Te6edf3nums Tff7b72= Te6edf3exportJsonTb4b4b4(Tb4b4b4)Tff7b72[Ta5d6ff"Ta5d6ffnodesTa5d6ff"Tff7b72]Tff7b72!!Tb4b4b4.Te6edf3jsonArrayTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3jsonObjectTff7b72[Ta5d6ff"Ta5d6ffnumTa5d6ff"Tff7b72]Tff7b72?.Te6edf3jsonPrimitiveTff7b72?.Te6edf3int Tb4b4b4}

Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff2Tb4b4b4, T79c0ff3Tb4b4b4, T79c0ff1Tb4b4b4)Tb4b4b4, Te6edf3numsTb4b4b4)
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.1s